package com.haiyou.sdk.account;

import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.haiyou.common.constants.ErrCode;
import com.haiyou.common.constants.ErrorCode;
import com.haiyou.common.constants.game.GameConstants;
import com.haiyou.common.constants.sdk.AccountConstants;
import com.haiyou.common.constants.sdk.ChannelConstants;
import com.haiyou.common.event.asyc.AsyncEventBuses;
import com.haiyou.common.http.HttpResult;
import com.haiyou.common.http.HttpResultUtils;
import com.haiyou.common.jdbc.DbType;
import com.haiyou.common.system.Properties;
import com.haiyou.common.util.check.Assert;
import com.haiyou.common.util.http.HttpUtils;
import com.haiyou.common.util.ip.IpUtil;
import com.haiyou.common.util.string.StringUtil;
import com.haiyou.common.util.time.ServerTime;
import com.haiyou.common.util.time.TimeUtil;
import com.haiyou.common.util.uid.IdUtils;
import com.haiyou.data.game.report.*;
import com.haiyou.data.game.role.*;
import com.haiyou.data.sdk.account.*;
import com.haiyou.data.sdk.account.token.AccountTokenService;
import com.haiyou.data.sdk.account.token.AdminToken;
import com.haiyou.data.sdk.event.RegisterEvent;
import com.haiyou.protocol.http.sdk.login.AuthRequest;
import com.haiyou.protocol.http.sdk.player.*;
import com.haiyou.sdk.log.LogService;
import com.haiyou.sdk.log.LogType;
import com.haiyou.sdk.rank.RankScoreEntity;
import com.haiyou.sdk.rank.RankScoreRank;
import com.haiyou.sdk.thirdSdk.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Sets;
import org.redisson.client.protocol.ScoredEntry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 账号系统
 *
 * @author xingyuan
 * @Date 2023年6月19日 上午11:45:53
 */
@Slf4j
@Component
public class AccountService {

    public static char[] id_char = {'d', '7', 'e', '2', 'b', '5', '8', 'f', '0', '6', '3', 'a', '1', '9', 'c', '4'};

    public static char[] id_char_addtion = {'7', 'e', '2', 'b', '5', '8', 'f', '0', 'd', '6', '3', 'a', '1', '9', 'c', '4'};

    public static int[] id_real_index = {0, 3, 4, 6, 8, 11, 14, 17, 19, 23};

    /**
     * 是否保存广告
     */
    public static boolean saveAdv = true;

    public static final String report_key_jump_times = "jumpTimes";
    public static final String report_key_head_frame_times = "headFrameTimes";
    public static final String report_key_download_head_frame_times = "downloadHeadFrameTimes";
    public static final String report_key_share_head_frame_times = "shareHeadFrameTimes";
    public static final String report_key_watch_adv_times = "watchAdvTimes";
    public static final String report_key_login = "login";
    public static final String report_key_login_times = "loginTimes";

    /**
     * 每日埋点
     */
    public static Set<String> report_key_daily = Sets.newHashSet(report_key_watch_adv_times, report_key_login);

    /**
     * 玩家埋点统计
     */
    public static Set<String> report_key_statistics = Sets.newHashSet(report_key_jump_times,
            report_key_head_frame_times, report_key_download_head_frame_times, report_key_share_head_frame_times,
            report_key_login);

    /**
     * 一共24位，10位为玩家真实id 另外14位为部位id
     *
     * @param playerId
     * @return
     */
    private static String getClientId(long playerId, long createTime) {
        createTime = createTime * playerId;
        StringBuffer sb = new StringBuffer();
        for (int index : id_real_index) {

            while (index > sb.length()) {

                long idx = createTime % 10;
                if (idx < 0) {
                    idx = -idx;
                }
//				System.out.println(createTime+" "+idx);

//				System.out.println(createTime +"补位"+id_char_addtion[(int)idx]);

                createTime = createTime / 10;

                sb.append(id_char_addtion[(int) idx]);
            }

            long idx = playerId % id_char.length;
            playerId = playerId / id_char.length;
            sb.append(id_char[(int) idx]);
        }

        return sb.toString();
    }

    public static void main(String[] args) {
        System.out.println((int) Math.pow(16, 3));
        System.out.println(getClientId(104001098, System.currentTimeMillis()));
        System.out.println(getClientId(102001001, System.currentTimeMillis() + TimeUtil.DAY));
        System.out.println(getClientId(101001009, System.currentTimeMillis() + 5 * TimeUtil.DAY));
        System.out.println(reverseClientId("3d7bcbc8ee62808bfdfd652d"));
        System.out.println(reverseClientId("6fd86d8eb66757806d0d226d"));
        System.out.println(reverseClientId("78d2ffed5d8d628fbdddf5fd"));
    }


    public static long reverseClientId(String id) {
        long result = 0L;
        for (int index = 0; index < id_real_index.length; index++) {
            char ch = id.charAt(id_real_index[index]);
            int idx = 0;
            int counter = 0;
            for (char c : id_char) {
                if (ch == c) {
                    idx = counter;
                    break;
                }
                counter++;
            }
            result = result + idx * (int) Math.pow(16, index);
        }
        return result;
    }

    @Autowired
    private PlayerRoleTableAccessor roleTableAccessor;
    @Autowired
    private PlayerTableAccessor playerTableAccessor;

    @Autowired
    private AccountTokenService tokenService;

    @Autowired
    private SdkAccountTableAccessor accountTableAccessor;

    @Autowired
    private UidAccountIdTableAccessor uidAccountIdTableAccessor;

    @Autowired
    private ReportLogAccessor reportLogAccessor;
    @Autowired
    private PlayerReportTableAccessor playerReportTableAccessor;

    @Autowired
    private HaiYoSdkService haiYoSdkService;

    @Autowired
    private AiWanSdkService aiWanSdkService;
    @Autowired
    private LogService logService;
    @Autowired
    private PlayerAdvertRecordTableAccessor playerAdvertRecordTableAccessor;
    @Autowired
    private UidTableAccessor uidTableAccessor;
    private static String EMPTY_STRING = "";

    private static String EFFECT_STRING = "1";

    /**
     * 关闭自动定位
     */
    private static String PROPERTY_KEY_CLOSE_AUTO_LOCATION = "closeAutoLocation";
    /**
     * 自动定位
     */
    private static String PROPERTY_KEY_AUTO_LOCATION = "autoLocation";
    /**
     * 修改定位
     */
    private static String PROPERTY_KEY_CHANGE_LOCATION = "changeLocation";
    /**
     * 更新排行榜key
     */
    private static String PROPERTY_KEY_UPDATE_RANK_KEY = "gainFrameHopeReward";

    private boolean validAdminLogin(String uid) {
        AdminToken token = tokenService.getAdminTokenById(uid);
        if (token != null && token.getExpireTime() > System.currentTimeMillis()) {
            return true;
        }
        return false;
    }


    /**
     * @param id       数据id
     * @param username 用户名/账号/邮箱/手机号/sdkUid
     * @param phone    手机号
     * @param password 密码
     * @param channel  渠道
     * @return
     */
    public SdkAccountTable register(String id, String username, String phone, String password, String channel) {

        Assert.isTrue(StringUtils.hasLength(id), ErrCode.ERROR_PARAMETER, "注册出现异常 id：{}");
        Assert.isTrue(StringUtils.hasLength(channel), ErrCode.ERROR_PARAMETER, "注册出现异常 channel：{}");
        Assert.isTrue(StringUtils.hasLength(username), ErrCode.ERROR_PARAMETER, "注册出现异常 username：{}");

        UidAccountIdTable uidAccountIdTable = new UidAccountIdTable();
        long currentUid = accountTableAccessor.getNextUid();
        if (currentUid == Properties.account_uid_begin_number_id() + 1) {
            //说明要么是新服，要么就是redis宕机后数据丢失了
            UidTable uidTable = uidTableAccessor.get(0L);
            if (uidTable != null) {
                currentUid = uidTable.getUid() + 1;
                accountTableAccessor.setNextUid(currentUid);
                playerTableAccessor.setNextPlayerId(uidTable.getPlayerId() + 1);
            }
            log.info("重新加载用户id游标,{}", currentUid);
        }
        PlayerRoleTable playerRoleTable = roleTableAccessor.getByUid(String.valueOf(currentUid));
        //报错就去修改redis 上的RAtomicLong__player_playerId_keyGenerator 和 RAtomicLong__acct_uid_keyGenerator的值
        Assert.isTrue(playerRoleTable == null, ErrCode.ERROR_PARAMETER, "注册出现异常 账号已存在：{},{}", playerRoleTable, currentUid);

        // 密码进行加密
        SdkAccountTable accountTable = accountTableAccessor.compute(id, (k, v) -> {

            if (!ObjectUtils.isEmpty(v)) {
                return v;
            }
            v = new SdkAccountTable();
            v.setId(k);
            v.setCreateTime(ServerTime.timeMillis());
            v.setPhone(phone);
            String uid = accountTableAccessor.uidNext();

            v.setUid(uid);
            v.setUsername(username);
            v.setChannel(channel);

            if (!StringUtils.hasLength(phone)) {
                v.setPhone(AccountConstants.not_bind_phone);
            }

            v.setEmail(AccountConstants.not_bind_mail);
            v.setPassword(password);

            uidAccountIdTable.setAccountId(k);
            uidAccountIdTable.setId(uid);

            return v;
        });

        // 创建数据
        uidAccountIdTableAccessor.compute(uidAccountIdTable.getId(), (k, v) -> {
            return uidAccountIdTable;
        });

        return accountTable;
    }


    /**
     * 直接创建版本
     *
     * @param request
     * @return
     */
    public HttpResult authTokenV1(AuthRequest request, HttpServletRequest httpServletRequest) {

        // 登录uid
        String uid = request.getUid();
        // token
        String token = request.getToken();
        // 渠道
        String channel = request.getChannel();

        log.info("uid={},token={},channel={}", uid, token, channel);

        channel = ChannelConstants.convert(channel);

        request.setChannel(channel);

        // 需要能处理的渠道
        Assert.isTrue(ChannelConstants.contain(channel), ErrorCode.ERROR_PARAMETER);

        Assert.isTrue(StringUtils.hasLength(channel), ErrorCode.ERROR_PARAMETER);

        Assert.isTrue(StringUtils.hasLength(token) || StringUtils.hasLength(uid), ErrorCode.ERROR_PARAMETER);

        String username = EMPTY_STRING;

        boolean adminLogin = false;

        // 存在特殊token
        if (StringUtils.hasLength(Properties.game_admin_login_token())) {

            if (Properties.game_admin_login_token().equals(token)) {
                adminLogin = true;
                username = request.getUid();
            }
        }

        // 超登
        int source = 0;
        if (!adminLogin) {
            switch (channel) {
                // 嗨哟登录
                case ChannelConstants.haiyou: {
                    username = haiYoSdkService.authSign(request);
                    break;
                }
                case ChannelConstants.wechat: {
                    username = WeChatSdkService.authSign(request);
                    source = 1;
                    break;
                }
                case ChannelConstants.douyin: {
                    username = DouyinSdkService.authSign(request);
                    source = 2;
                    break;
                }
                case ChannelConstants.aiwan: {
                    username = aiWanSdkService.authSign(request);
                    break;
                }
                case ChannelConstants.aiwan_cn: {
                    username = aiWanSdkService.authSign(request);
                    break;
                }

                case ChannelConstants.aiwan_xx: {
                    username = aiWanSdkService.authSign(request);
                    break;
                }
                case ChannelConstants.kuaishou: {
                    username = KuaiShouSdkService.authSign(request);
                    source = 3;
                    break;
                }
                default: {
                    Assert.isTrue(false, ErrorCode.ERROR_PARAMETER);
                }
            }
        }

        String id = IdUtils.createId(username, request.getChannel());

        SdkAccountTable accountTable = accountTableAccessor.get(id);

        if (ObjectUtils.isEmpty(accountTable)) {
            accountTable = register(id, username, EMPTY_STRING, AccountConstants.not_set_password, request.getChannel());
        } else {
            // 判断是否正在超登中，超登中阻断正常登录
            if (validAdminLogin(accountTable.getUid())) {
                log.error("账号超登中,id:{}", id);
                return HttpResultUtils.failResult(ErrCode.ACCOUNT_LOCKED, "账号锁定中,请联系管理员");
            }
        }
        boolean needCreate = readyRegister(accountTable.getUid(), 1);
        // 回包
        PlayerInfoResponse response = new PlayerInfoResponse();
        PlayerTable playerTable = loginQuery(accountTable.getUid(), 1, null, source);

        response.setUid(accountTable.getUid());
        response.setToken(String.valueOf(playerTable.getPlayerId()));
        response.setPlayerId(getClientId(playerTable.getPlayerId(), playerTable.getCreateTime()));
        response.setCreateTime(playerTable.getCreateTime());
        response.setCreateBehavior(needCreate);
        response.setIp(IpUtil.getIpAddr(httpServletRequest));
        log.info("playerId:{},ip:{}", playerTable.getPlayerId(), response.getIp());
        try {
            UpdateDataRequest req = new UpdateDataRequest();
            req.setKey(report_key_login);
            report(playerTable.getPlayerId(), req, playerTable);
        } catch (Exception e) {
            log.error("埋点失败", e);
        }
        logService.logLogin(playerTable.getPlayerId(), source);
        if (channel.equals(ChannelConstants.douyin) && request.getDyCallback() != null && !request.getDyCallback().isEmpty()) {
            if (needCreate) {
                dyAdvertReported(playerTable.getPlayerId(), "active_register", request.getDyCallback());
                dyAdvertReported(playerTable.getPlayerId(), "create_gamerole", request.getDyCallback());
            } else {
                if (TimeUtil.getIntervalDay(playerTable.getCreateTime(), System.currentTimeMillis()) == 1) {
                    //次留上报
                    dyAdvertReported(playerTable.getPlayerId(), "next_day_open", request.getDyCallback());
                }
            }
        }
        if (!needCreate && request.getReportUid() != null && !request.getReportUid().isEmpty()) {
            logService.deleteLog(playerTable.getPlayerId(), request.getReportUid());
        }
        return HttpResultUtils.successResult(response);
    }

    /**
     * 登录查询
     *
     * @param uid
     * @param serverId
     * @param ai       ai类型
     * @return
     */
    public PlayerTable loginQuery(String uid, int serverId, String name, int source) {
        return queryPlayerTable(uid, serverId, name, source);
    }

    /**
     * 查询玩家信息
     *
     * @param uid
     * @param serverId
     * @return
     */
    public PlayerTable queryPlayerTable(String uid, int serverId, String name, int source) {

        PlayerRoleTable playerRoleTable = roleTableAccessor.getByUid(uid);

        if (playerRoleTable == null) {

            String key = roleTableAccessor.generateKey(uid);

            playerRoleTable = roleTableAccessor.compute(key, (k, v) -> {

                if (v == null) {
                    v = new PlayerRoleTable();
                    v.setId(k);
                    v.setUid(uid);
                }
                return v;
            });
        }

        long playerId = playerRoleTable.getRoles().getOrDefault(serverId, -1l);

        PlayerTable playerTable = null;

        if (playerId <= 0) {
            // 注册用户角色信息
            playerTable = register(uid, serverId, name, source);
        } else {
            playerTable = playerTableAccessor.get(playerId);
            if (playerTable != null && (playerTable.getDeviceId() == null || playerTable.getDeviceId().isEmpty() || Integer.parseInt(playerTable.getDeviceId()) != source)) {
                playerTableAccessor.compute(playerTable.getId(), (k, v) -> {
                    if (v == null) {
                        return v;
                    }
                    //赋渠道值区分玩家来源
                    v.setDeviceId(String.valueOf(source));
                    return v;
                });
            }
        }
        return playerTable;
    }

    /**
     * 是否需要注册
     *
     * @param uid
     * @param serverId
     * @return
     */
    public boolean readyRegister(String uid, int serverId) {
        PlayerRoleTable playerRoleTable = roleTableAccessor.getByUid(uid);
        if (playerRoleTable == null) {
            return true;
        }
        long playerId = playerRoleTable.getRoles().getOrDefault(serverId, -1l);
        return playerId <= 0;
    }

    /**
     * 注册玩家
     *
     * @param uid
     */
    public PlayerTable register(String uid, int serverId, String name, int source) {

        // 创建玩家数据
        long playerId = playerTableAccessor.playerIdNext();
        // 初始名称

        if (ObjectUtils.isEmpty(name)) {
            StringBuffer sbName = new StringBuffer();
            sbName.append(playerId);
            name = sbName.toString();
        }

        Date now = new Date();
        PlayerTable playerTable = playerTableAccessor.compute(playerId, (k, v) -> {

            if (v == null) {
                v = new PlayerTable();
                v.setId(k);
                v.setPlayerId(playerId);
                v.setUid(uid);
                v.setLoginTime(now);
                v.setServerId(serverId);
                v.setDeviceId(String.valueOf(source));
            }

            return v;
        });

        // 创建playerInfo

        String key = roleTableAccessor.generateKey(uid);

        roleTableAccessor.compute(key, (k, v) -> {
            v.getRoles().put(serverId, playerId);
            return v;
        });
        uidTableAccessor.compute(0L, (k, v) -> {
            if (v == null) {
                v = new UidTable();
                v.setId(0L);
                v.setUid(0L);
            }
            long currentId = Long.parseLong(playerTable.getUid());
            if (currentId <= v.getUid()) {
                return v;
            }
            v.setPlayerId(playerId);
            v.setUid(currentId);
            return v;
        });

        // 抛出注册事件
        AsyncEventBuses.getInstance().postEvent(RegisterEvent.build(uid, playerId, serverId));
        log.info("注册完成：{},{}", playerId, source);
        logService.logRegister(playerId, source, playerTable.getUid());
        return playerTable;
    }

    /**
     * 验证token
     *
     * @param request
     * @return
     */


    // TODO 验证token

    /**
     * 获得多键对应的value
     *
     * @param request
     * @return
     */
    public HttpResult getData(GetDataRequest request) {
        if (ObjectUtils.isEmpty(request.getKeys())) {
            HttpResultUtils.failResult(ErrCode.ERROR_PARAMETER, "没有参数");
        }

        long playerId = getPlayerIdByToken(request.getToken());

        List<String> keys = StringUtil.parseListByString(request.getKeys(), GameConstants.PARSE_COMMA);
        PlayerTable table = playerTableAccessor.get(playerId);
        if (table == null) {
            return HttpResultUtils.failResult(ErrCode.ERROR_PARAMETER, "账号验证错误");
        }

        Map<String, String> result = Maps.newHashMap();
        HashMap<String, String> data = table.getData();
        for (String key : keys) {
            String value = data.getOrDefault(key, EMPTY_STRING);
            result.put(key, value);
        }

        GetDataResponse resp = new GetDataResponse();
        resp.setData(result);
        return HttpResultUtils.successResult(resp);
    }

    private long getPlayerIdByToken(String token) {
        return Long.parseLong(token);
    }

    /**
     * 更新key值
     *
     * @param request
     * @return
     */
    public HttpResult updateData(UpdateDataRequest request) {
        if (ObjectUtils.isEmpty(request.getKey())) {
            HttpResultUtils.failResult(ErrCode.ERROR_PARAMETER, "没有参数k");
        }

        long playerId = getPlayerIdByToken(request.getToken());

        PlayerTable table = playerTableAccessor.compute(playerId, (k, v) -> {
            if (v == null) {
                return v;
            }
            v.getData().put(request.getKey(), request.getValue());
            return v;
        });

        if (table == null) {
            return HttpResultUtils.failResult(ErrCode.ERROR_PARAMETER, "账号验证错误");
        }

        Map<String, String> result = Maps.newHashMap();
        result.put(request.getKey(), table.getData().getOrDefault(request.getKey(), EMPTY_STRING));
        GetDataResponse resp = new GetDataResponse();
        resp.setData(result);

        // 如果是通关，更新排行榜
        if (request.getKey().equals(PROPERTY_KEY_UPDATE_RANK_KEY)) {
            updateRank(table, 1);
        }

        try {
            report(playerId, request, table);
        } catch (Exception e) {
            log.error("埋点失败", e);
        }

        return HttpResultUtils.successResult(resp);
    }

    /**
     * 埋点
     *
     * @param request
     * @param playerTable
     */
    private void report(long playerId, UpdateDataRequest request, PlayerTable playerTable) {
        String key = request.getKey();
        // 指定上报才会保存数据
        if (!report_key_daily.contains(key) && !report_key_statistics.contains(key)) {
            return;
        }

        if (report_key_daily.contains(key) && saveAdv) {
            reportLogAccessor.compute(playerId, (k, v) -> {
                if (v == null) {
                    v = new ReportLog();
                    v.setId(k);
                    v.setPlayerId(playerId);
                }
                switch (key) {
                    case report_key_login:
                        v.setLoginTimes(v.getLoginTimes() + 1);
                        return v;
                    case report_key_watch_adv_times:
                        v.setAdvTimes(v.getAdvTimes() + 1);
                        return v;
                }
                return v;
            });
        }

        if (report_key_statistics.contains(key)) {
            playerReportTableAccessor.compute(playerId, (k, v) -> {
                if (v == null) {
                    v = new PlayerReportTable();
                    v.setId(k);
                    v.setPlayerId(playerId);
                }
                v.setOperateTime(Calendar.getInstance().getTime());
                switch (key) {
                    case report_key_login:
                        return v;
                    case report_key_download_head_frame_times:
                        v.setDownloadHeadTimes(v.getDownloadHeadTimes() + 1);
                        return v;
                    case report_key_head_frame_times:
                        v.setHeadTimes(v.getHeadTimes() + 1);
                        return v;
                    case report_key_jump_times:
                        int loginTimes = Integer.parseInt(playerTable.getData().getOrDefault(report_key_login_times, "0"));
                        if (loginTimes <= 1) {
                            v.setJump1(v.getJump1() + 1);
                        } else if (loginTimes == 2) {
                            v.setJump2(v.getJump2() + 1);
                        } else if (loginTimes == 3) {
                            v.setJump3(v.getJump3() + 1);
                        }
                        return v;
                    case report_key_share_head_frame_times:
                        v.setShareHeadTimes(v.getShareHeadTimes() + 1);
                        return v;
                }
                return v;
            });
        }
    }

    private int getLocation(PlayerTable table) {
        HashMap<String, String> data = table.getData();
        // 关闭定位
        if (EFFECT_STRING.equals(data.getOrDefault(PROPERTY_KEY_CLOSE_AUTO_LOCATION, EMPTY_STRING))) {
            return 0;
        }

        // 修改过定位
        String chagneLocation = data.get(PROPERTY_KEY_CHANGE_LOCATION);
        if (!ObjectUtils.isEmpty(chagneLocation)) {
            int change = Integer.parseInt(chagneLocation);
            if (change > 0) {
                return change;
            }
        }
        // 自动定位
        String autoLocation = data.get(PROPERTY_KEY_AUTO_LOCATION);
        if (!ObjectUtils.isEmpty(autoLocation)) {
            return Integer.parseInt(autoLocation);
        }
        return 0;
    }

    /**
     * 更新排行榜排名
     */
    private void updateRank(PlayerTable player, int addition) {
        // 所在区县榜单
        int areaId = getLocation(player);
        // 区县排行榜
        int cityId = areaId / 100 * 100;

        // 今日0点时间
        RankScoreRank rank = RankScoreRank.build(cityId, DbType.GAME_DB);
        // 更新排行榜
        rank.updateRank(new RankScoreEntity((long) areaId, addition));
        // 市排行榜
        int cId = areaId / 10000 * 10000;
        if (cId != cityId) {
            rank = RankScoreRank.build(cId, DbType.GAME_DB);
            // 更新排行榜
            rank.updateRank(new RankScoreEntity((long) cityId, addition));
        }

        // 省排行榜
        int proId = areaId / 1000000 * 1000000;
        if (proId != cId) {
            rank = RankScoreRank.build(proId, DbType.GAME_DB);
            // 更新排行榜
            rank.updateRank(new RankScoreEntity((long) cId, addition));
        }
    }

    /**
     * 省市区县排行榜
     *
     * @return
     */
    public HttpResult getRank(GetRankRequest request) {
        // 如果是四个直辖市 特殊处理id
        int locationId = request.getId();
        if (locationId == 110000 || locationId == 120000 || locationId == 310000 || locationId == 500000) {
            locationId = locationId + 100;
        }
        RankScoreRank rank = RankScoreRank.build(locationId, DbType.GAME_DB);
        Collection<ScoredEntry<Long>> ranks = rank.getRankAllData(500);
        List<List<Long>> rankResult = Lists.newArrayList();
        for (ScoredEntry<Long> r : ranks) {
            rankResult.add(Lists.newArrayList(r.getValue(), r.getScore().longValue()));
        }
        return HttpResultUtils.successResult(rankResult);
    }

    /**
     * 腾讯行为上报
     *
     * @param request
     * @return
     */
    public HttpResult tencentBehaviorReported(ReportedRequest request) {
/*		String url = "https://api.e.qq.com/v1.3/user_actions/add"+"?access_token=29cd7a9130fbcddc1d3de9d63164510f"
				+ "&timestamp=" + TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())
				+ "&nonce=" + UUID.randomUUID();*/

        String url = "https://api.e.qq.com/v1.3/user_actions/add" + "?access_token=" + request.getAccessToken()
                + "&timestamp=" + request.getTimestamp()
                + "&nonce=" + request.getNonce();

        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");

		/*JSONObject actions = new JSONObject();
		actions.put("action_time", TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()));
		JSONObject userId = new JSONObject();
		userId.put("wechat_openid","9dbd70c65024e75b6ddd58bd");
		userId.put("wechat_app_id","wx6a174f7e85bd276c");
		actions.put("user_id",userId);
		actions.put("action_type","CUSTOM");
		actions.put("outer_action_id",UUID.randomUUID().toString());
		JSONObject actionParams = new JSONObject();
		actionParams.put("trust",1);
		actions.put("action_param",actionParams);
		actions.put("custom_action","test_123");
		actions.put("channel","TENCENT");
		JSONObject body = new JSONObject();
		body.put("account_id",53648357);
		body.put("user_action_set_id",1210100883);
		body.put("actions",new JSONArray(actions));*/

        JSONObject body = new JSONObject();
        body.put("account_id", request.getAccountId());
        body.put("user_action_set_id", request.getUserActionSetId());
        body.put("actions", request.getActions());
        try {
            String response = HttpUtils.postBody(url, body.toJSONString(), headers);
            System.out.println(response);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return HttpResultUtils.successResult();
    }

    /**
     * 抖音归化上报
     */
    private void dyAdvertReported(long playerId, String eventType, String callback) {
        JSONObject data = new JSONObject();
        data.put("event_type", eventType);
        JSONObject context = new JSONObject();
        JSONObject ad = new JSONObject();
        ad.put("callback", callback);
        context.put("ad", ad);
        data.put("context", context);
        JSONObject properties = new JSONObject();
        properties.put("playerId", playerId);
        data.put("properties", properties);
        data.put("timestamp", System.currentTimeMillis());
        String body = data.toJSONString();
        DouYinReportedRequest request = new DouYinReportedRequest();
        request.setRequestBody(body);
        douYinBehaviorReported(request);
    }


    /**
     * 抖音行为上报
     *
     * @param request
     * @return
     */
    public HttpResult douYinBehaviorReported(DouYinReportedRequest request) {

        String url = "https://analytics.oceanengine.com/api/v2/conversion";
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        try {
            log.info("dou yin report:{}", request);
            String response = HttpUtils.postBody(url, request.getRequestBody(), headers);
            System.out.println(response);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return HttpResultUtils.successResult();
    }


    /**
     * 观看广告上报
     *
     * @param request
     * @return
     */
    public HttpResult logReported(LogRequest request) {
        LogType type = LogType.getByType(request.getType());
        if (request.getPlayerId() != null && !request.getPlayerId().isEmpty()) {
            UidAccountIdTable uidAccountIdTable = uidAccountIdTableAccessor.get(request.getPlayerId());
            //除去广告、新老关卡，其他数据老用户不关注
            if (uidAccountIdTable != null && !type.equals(LogType.advert) && !type.equals(LogType.stage) && !type.equals(LogType.newStage)) {
                SdkAccountTable sdkAccountTable = accountTableAccessor.get(uidAccountIdTable.getAccountId());
                if (sdkAccountTable != null && TimeUtil.getCountDay(new Date(sdkAccountTable.getCreateTime())) != TimeUtil.getCountDay(new Date())) {
                    return HttpResultUtils.successResult();
                }
            }
        }
        switch (type) {
            case advert: {
                if (request.getPlayerId() == null || request.getPlayerId().isEmpty()) {
                    log.error("AccountService.logReported playerId is null");
                    break;
                }
                long playerId = Long.parseLong(request.getPlayerId());
                AtomicBoolean status = new AtomicBoolean(false);
                PlayerAdvertRecordTable table = playerAdvertRecordTableAccessor.compute(playerId, (k, v) -> {
                    if (v == null) {
                        v = new PlayerAdvertRecordTable();
                        v.setId(k);
                        v.setPlayerId(playerId);
                        v.setUpdateTime(0);
                        v.setAdvertId("");
                    }
                    if (request.getAdvertId().equals(v.getAdvertId()) && System.currentTimeMillis() - v.getUpdateTime() <= TimeUnit.SECONDS.toMillis(1)) {
                        return v;
                    }
                    v.setAdvertId(request.getAdvertId());
                    v.setUpdateTime(System.currentTimeMillis());
                    status.set(true);
                    return v;
                });
                if (!status.get()) {
                    log.info("广告上报失败，重复上报,request:{}, table:{}", request, table);
                    break;
                }
                log.info("广告上报 request：{}", request);
                logService.logAdvert(request.getPlayerId(), request.getAdvertType(), request.getAdvertId(), request.isStatus(), request.getServerId());
                break;
            }
            case newStage:
            case stage: {
                logService.logStage(request.getType(),request.getPlayerId(), request.getLogId(),request.getServerId());
                break;
            }
            case open: {
                String uuid = UUID.randomUUID().toString();
                String finalUUID = uuid.replace("-", "a");
                log.info("open uuid:{}", finalUUID);
                logService.logOpen(finalUUID, request.getServerId());
                return HttpResultUtils.successResult(finalUUID);
            }
            case start: {
                log.info("start request uuid:{}", request.getReportUid());
                logService.logStart(request.getReportUid(), request.getServerId());
                return HttpResultUtils.successResult();
            }
            case guideClose:
            case userInfoAuthorize:
            case rewardFrame:
            case guideShow:
            case firstStageScore:
            case firstResult:
            case firstResultAdClick: {
                logService.logExtra(request.getType(), request.getPlayerId(), request.getLogId(), request.getServerId());
                break;
            }
            default: {
                break;
            }
        }
        return HttpResultUtils.successResult();
    }

    public HttpResult getClientIp(HttpServletRequest httpServletRequest) {
        String ipAddr = IpUtil.getIpAddr(httpServletRequest);
        log.info("ip:{}", ipAddr);
        return HttpResultUtils.successResult(ipAddr);
    }
}
